#include <iostream>
#include <string>

/* 下面的用例演示了，虚函数基继承和使用的方法，通过下面两种方式实现多态 */
/* 1. 通过将子类地址传给父类指针，调用子类的虚函数 */
/* 2. 通过将子类引用传给父类引用，调用子类的虚函数 */

/* 抽象类 */
class animal
{
  public:
    virtual void sound() = 0;
    virtual void move() = 0;
    virtual void eat() = 0;
    virtual void get_type_and_age() = 0;
    virtual void get_description() = 0;
    animal(int type = 0, int age = 0, std::string des = "")
        : type(type), age(age), description(des)
    {
    }

  protected:
    int type;
    int age;
    std::string description;
};

/* final关键字，不允许该子类再被继承 */
class dog final : public animal
{
  public:
    /* 每个参数都有默认值，如果没有传入参数，则使用默认值 */
    dog(int type = 0, int age = 0, std::string des = "")
        : animal(type, age, des)
    {
    }
    /* 使用 override
     * 关键字，子类重写父类虚函数的时候，会检查父类是否有此虚函数，如果没有则编译会报错
     */
    void sound() override { std::cout << "Bark" << std::endl; }
    void move() override { std::cout << "Run" << std::endl; }
    void eat() override { std::cout << "Meat" << std::endl; }
    void get_type_and_age() override
    {
        std::cout << "Type: " << type << " Age: " << age << std::endl;
    }
    void get_description() override { std::cout << description << std::endl; }
};

class cat final : public animal
{
  public:
    cat(int type = 0, int age = 0, std::string des = "")
        : animal(type, age, des)
    {
    }
    void sound() override { std::cout << "Meow" << std::endl; }
    void move() override { std::cout << "Jump" << std::endl; }
    void eat() override { std::cout << "Fish" << std::endl; }
    void get_type_and_age() override
    {
        std::cout << "Type: " << type << " Age: " << age << std::endl;
    }
    void get_description() override { std::cout << description << std::endl; }
};

void animal_actions(animal &animal_type)
{
    animal_type.sound();
    animal_type.move();
    animal_type.eat();
    animal_type.get_type_and_age();
    animal_type.get_description();
}

void animal_actions(animal *animal_type)
{
    animal_type->sound();
    animal_type->move();
    animal_type->eat();
    animal_type->get_type_and_age();
    animal_type->get_description();
}

int main()
{
    dog d(1, 2, "This ia a Dog");
    cat c(2, 4, "This is a Cat");
    animal_actions(d);
    animal_actions(c);
    std::cout << std::endl;

    animal_actions(&d);
    animal_actions(&c);
    return 0;
}